/**
 * @author Cator Vee  hi@catorv.com
 */
import {mixin} from '../utils'
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import env from '../lib/env'

export default class Spinner extends Component {
  constructor (props) {
    super(props)
    let options = mixin({
      lines: 12, // The number of lines to draw
      length: 4, // The length of each line
      width: 2, // The line thickness
      radius: 7, // The radius of the inner circle
      color: '#000' // [red, green, blue, alpha]
    }, props.options, true)

    const ratio = env.screen.pixelRatio
    if (ratio !== 1) {
      options.length *= ratio
      options.width *= ratio
      options.radius *= ratio
    }

    this.speed = 1000 / options.lines
    this.angle = Math.PI * 2 / options.lines
    if (props.size) {
      this.width = props.size
    } else {
      this.width = (options.radius + options.length + options.width) * 2
    }

    this.options = options
  }

  componentDidMount () {
    let options = this.options
    let size = this.width
    let halfSize = size >> 1

    const canvas = this.canvas
    const ctx = canvas.getContext('2d')
    canvas.width = canvas.height = size
    ctx.translate(halfSize, halfSize)
    ctx.lineWidth = options.width
    ctx.strokeStyle = options.color
    ctx.lineCap = 'round'

    this.timer = setTimeout(this.update.bind(this), this.speed)
  }

  componentWillUnmount () {
    clearTimeout(this.timer)
  }

  update () {
    if (this.canvas) {
      let options = this.options
      // let color = options.color
      let canvas = this.canvas
      let ctx = canvas.getContext('2d')

      // Rotate the origin
      // ctx.rotate(this.angle + options.rotate)
      ctx.rotate(this.angle)

      ctx.clearRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2)
      for (let i = 0; i < options.lines; i++) {
        // ctx.globalCompositeOperation = i === 0 ? 'source-out' : 'source-over'

        // Rotate the origin
        // ctx.rotate(this.angle + options.rotate)
        ctx.rotate(this.angle)

        // Set transparency
        ctx.globalAlpha = Math.max(i / options.lines, 0.1)

        ctx.beginPath()
        ctx.moveTo(0, options.radius)
        ctx.lineTo(0, options.radius + options.length)
        ctx.stroke()
      }
      setTimeout(this.update.bind(this), this.speed)
    }
  }

  render () {
    let ratio = env.screen.pixelRatio
    let width = this.width
    let w = width / ratio | 0
    let style = {
      width: w + 'px',
      height: w + 'px'
    }
    if (this.props.atCenter) {
      style = {
        ...style,
        position: 'absolute',
        left: '50%',
        top: '50%',
        marginTop: '-' + (w / 2 | 0) + 'px',
        marginLeft: '-' + (w / 2 | 0) + 'px'
      }
    }
    return (
      <canvas className={'spinner-view'} style={style} ref={el => { this.canvas = el }} />
    )
  }
}

Spinner.propTypes = {
  options: PropTypes.shape({
    lines: PropTypes.number, // The number of lines to draw
    length: PropTypes.number, // The length of each line
    width: PropTypes.number, // The line thickness
    radius: PropTypes.number, // The radius of the inner circle
    color: PropTypes.string // [red, green, blue, alpha]
  }),
  size: PropTypes.number,
  atCenter: PropTypes.bool
}

Spinner.defaultProps = {
  atCenter: true
}
